package com.github.cosycode.imgtool.ctrl;

import com.github.cosycode.common.ext.bean.DoubleBean;
import com.github.cosycode.common.lang.BaseRuntimeException;
import com.github.cosycode.common.lang.CheckException;
import com.github.cosycode.common.util.common.StrUtils;
import com.github.cosycode.common.util.encode.MessageDigestUtils;
import com.github.cosycode.common.util.io.IoUtils;
import com.github.cosycode.common.util.otr.PrintTool;
import com.github.cosycode.ext.se.util.FileUtils;
import com.github.cosycode.imgtool.rule.CheckConfig;
import com.github.cosycode.imgtool.rule.FileBatchExePlan;
import com.github.cosycode.imgtool.rule.FileExistCheckBRO;
import com.github.cosycode.imgtool.rule.MigrationPathConvert;
import com.github.cosycode.imgtool.tool.BaseTool;
import com.github.cosycode.imgtool.util.HttpUtils;
import com.github.cosycode.imgtool.util.PathUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;

import java.io.*;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;

import static com.github.cosycode.imgtool.tool.RegexUtils.MARKDOWN_IMG_REGEX_DIRECTOR;

/**
 * <b>Description : </b>
 * <p>
 * <b>created in </b> 2022/1/16
 * </p>
 *
 * @author CPF
 * @since 1.0
 **/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MarkdownImgLinkMigrationTool {

    /**
     * 按照规则进行替换
     *
     * @param txtFile 文本文件
     * @param config  检查配置
     * @param convert
     * @return 文件执行计划
     * @throws IOException txtFile 文件读取异常
     */
    public static FileBatchExePlan computeFileBatchExePlan(@NonNull File txtFile, @NonNull CheckConfig config, MigrationPathConvert convert) throws IOException {
        FileBatchExePlan plan = new FileBatchExePlan();
        String newContent = MarkdownFileProcessor.replaceMdImgLink(txtFile, config, rst -> {
            if (!rst.isExist()) {
                throw new CheckException("file is not exist ==> " + rst.getRealImgPath());
            }
            DoubleBean<String, String> pathBean = convert.computeTargetPath(config, txtFile, rst);
            String targetPath = pathBean.getO2();
            if (StringUtils.isNotBlank(targetPath)) {
                plan.addMoveRecord(URI.create(rst.getRealImgPath()), targetPath);
            }
            return pathBean.getO1();
        }, true);
        plan.changeContent(txtFile, newContent);
        return plan;
    }


    /**
     * 按照规则进行替换
     *
     * @param txtFile       文本文件
     * @param config        检查配置
     * @param imgTargetDir  图片移动目标文件夹
     * @param imgLinkPrefix markdown 里面图片链接的前缀部分, 与文件名组合成路径(targetPrefix/文件名)
     * @return
     * @throws IOException
     */
    public static FileBatchExePlan computeFileBatchExePlan(@NonNull File txtFile, @NonNull CheckConfig config, @NonNull String imgTargetDir, @NonNull String imgLinkPrefix) throws IOException {
        FileBatchExePlan plan = new FileBatchExePlan();
        List<FileExistCheckBRO> list = new ArrayList<>();
        String newContent = MarkdownFileProcessor.replaceMdImgLink(txtFile, config, rst -> {
            list.add(rst);
            return imgLinkPrefix + PathUtils.FILE_SPLIT_PATTERN + rst.getImgFileName();
        }, true);
        for (FileExistCheckBRO item : list) {
            if (!item.isExist()) {
                throw new FileNotFoundException(item.getRealImgPath());
            }
            plan.addMoveRecord(URI.create(item.getRealImgPath()), imgTargetDir + PathUtils.FILE_SPLIT_PATTERN + item.getImgFileName());
        }
        plan.changeContent(txtFile, newContent);
        return plan;
    }

    /**
     * 下载指定文件下的网络图片. 并保存到相应文件夹, 更改 md 文件
     */
    public static void downloadWebImg(@NonNull String rootDir, @NonNull List<File> files, Predicate<String> urlFilter, boolean dryRun) throws IOException {
        Map<String, String> map = new HashMap<>();
        CheckConfig config = new CheckConfig();
        config.setWebPathEnable(true, true);
        final String canonicalRootDir = PathUtils.getCanonicalPath(rootDir);
        for (File file : files) {
            AtomicBoolean changeFlag = new AtomicBoolean(false);
            // 分析文件编码
            final String s = FileUtils.analysisTextFileEncode(file);
            final Charset charset = Charset.forName(s);
            // 读取文件
            final String fileContext;
            try (final FileInputStream inputStream = new FileInputStream(file)) {
                fileContext = IoUtils.readStringFromInputStream(inputStream, charset);
            }
            // 将其中的 http 路径中的文件下载下来, 并放到本地路径, 并替换 URL
            final String newContext = StrUtils.replaceAll(MARKDOWN_IMG_REGEX_DIRECTOR, fileContext, path -> {
                if (urlFilter != null && !urlFilter.test(path)) {
                    return path;
                }
                if (map.containsKey(path)) {
                    return map.get(path);
                }
                final PathUtils.PathType pathType = PathUtils.getPathType(path);
                if (PathUtils.PathType.WEB_URL != pathType) {
                    return path;
                }
                /* 生成文件名, 文件名以路径的 MD5 码命名*/
                String imgTargetName = MessageDigestUtils.getMD5(path.getBytes());
                String extFromUrl = BaseTool.findExtFromUrl(path);
                // 生成保存路径
                String fileName = imgTargetName + "." + (extFromUrl != null ? extFromUrl : "PNG");
                String savePathStr = PathUtils.concatPathClips(canonicalRootDir, ".web-img", fileName);
                File saveFile = new File(savePathStr);
                // 下载图片
                boolean download = false;
                try {
                    if (!dryRun) {
                        download = HttpUtils.download(path, saveFile, null);
                    }
                } finally {
                    PrintTool.success("[file download {}] => {}", download ? "success" : "failed", path);
                }
                if (download) {
                    try {
                        String canonicalPath = saveFile.getCanonicalPath();
                        String subPath = StringUtils.removeStart(canonicalPath, canonicalRootDir);
                        Validate.isTrue(canonicalPath.length() > subPath.length(), "rootPath 没有匹配");
                        changeFlag.set(true);
                        String imgLink = PathUtils.concatPathClips("/", subPath);
                        map.put(path, imgLink);
                        return imgLink;
                    } catch (IOException e) {
                        throw new BaseRuntimeException("", e);
                    }
                } else {
                    return path;
                }
            });
            if (!dryRun && changeFlag.get()) {
                // 保存文件内容
                try (OutputStream outputStream = Files.newOutputStream(file.toPath())) {
                    IoUtils.writeStringToOutputStream(outputStream, newContext, charset);
                }
            } else {
                Validate.isTrue(newContext.equals(fileContext), PrintTool.format("newContext: {}\n\noriginalContext:{}", newContext, fileContext));
            }
        }
    }

}
